package com.webwork.common.util;

import java.sql.Timestamp;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;

/**
 * Java8新日期时间工具类
 * 
 */
public class DateTimeUtil {

	// 获取当前时间的LocalDateTime对象
//	LocalDateTime.now();

	// 根据年月日构建LocalDateTime
//	LocalDateTime.of();

	// 比较日期先后
//	LocalDateTime.now().isBefore(),
//	LocalDateTime.now().isAfter(),
	
	/**
	 * 系统默认时区
	 */
	private static ZoneId systemDefaultZone = ZoneId.systemDefault();

	/**
	 * 使用系统默认时区zone,根据时间戳的毫秒转成LocalDateTime类型
	 * @param millis
	 * @return
	 */
	public static LocalDateTime millisToLocalDateTime(long millis) {
		return millisToLocalDateTime(systemDefaultZone, millis);
	}
	
	/**
	 * 使用自定义时区zone,根据时间戳的毫秒转成LocalDateTime类型
	 * @param millis
	 * @return
	 */
	public static LocalDateTime millisToLocalDateTime(ZoneId zone, long millis) {
		Instant instant = Instant.ofEpochMilli(millis);
		LocalDateTime ldt = LocalDateTime.ofInstant(instant, zone);
		return ldt;
	}
	
	/**
	 * 使用系统默认时区zone,根据时间戳的毫秒转成LocalDate类型
	 * @param millis
	 * @return
	 */
	public static LocalDate millisToLocalDate(long millis) {
		return millisToLocalDate(systemDefaultZone, millis);
	}
	
	/**
	 * 使用自定义时区zone,根据时间戳的毫秒转成LocalDate类型
	 * @param millis
	 * @return
	 */
	public static LocalDate millisToLocalDate(ZoneId zone, long millis) {
		Instant instant = Instant.ofEpochMilli(millis);
		LocalDateTime ldt = LocalDateTime.ofInstant(instant, zone);
		return ldt.toLocalDate();
	}
	
	/**
	 * 在系统默认时区获取LocalDateTime的毫秒数
	 * @param ldt
	 * @return
	 */
	public static Long getMilliSecond(LocalDateTime ldt) {
		if (null == ldt) {
			return 0L;
		}
		return ldt.atZone(systemDefaultZone).toInstant().toEpochMilli();
	}
	
	/**
	 * 根据指定时区获取LocalDateTime毫秒数
	 * @param zone
	 * @param ldt
	 * @return
	 */
	public static Long getMilliSecond(ZoneId zone, LocalDateTime ldt) {
		if (null == ldt) {
			return 0L;
		}
		return ldt.atZone(zone).toInstant().toEpochMilli();
	}
	
	/**
	 * LocalDate的毫秒数
	 * 使用atStartOfDay转成LocalDateTime
	 * @param ldt
	 * @return
	 */
	public static Long getMilliSecond(LocalDate ld) {
		return getMilliSecond(ld.atStartOfDay());
	}
	
	/**
	 * sql时间戳转LocalDateTime
	 * @param timestamp
	 * @return
	 */
	public static LocalDateTime timestampToLocalDateTime(Timestamp timestamp) {
		return timestampToLocalDateTime(systemDefaultZone, timestamp);
	}
	
	/**
	 * sql时间戳转LocalDateTime
	 * @param zone
	 * @param timestamp
	 * @return
	 */
	public static LocalDateTime timestampToLocalDateTime(ZoneId zone, Timestamp timestamp) {
		return timestamp.toLocalDateTime();
	}
	
	/**
	 * sql时间戳转LocalDate
	 * @param timestamp
	 * @return
	 */
	public static LocalDate timestampToLocalDate(Timestamp timestamp) {
		return timestampToLocalDateTime(timestamp).toLocalDate();
	}
	
	/**
	 * sql时间戳转LocalDate
	 * @param zone
	 * @param timestamp
	 * @return
	 */
	public static LocalDate timestampToLocalDate(ZoneId zone, Timestamp timestamp) {
		return timestampToLocalDateTime(zone, timestamp).toLocalDate();
	}
	
	/**
	 * LocalDateTime转成Date
	 * @param ldt
	 * @return
	 */
	public static Date localDateTimeToDate(LocalDateTime ldt) {
		return Date.from(ldt.atZone(systemDefaultZone).toInstant());
	}
	
	/**
	 * LocalDate转成Date
	 * @param ld
	 * @return
	 */
	public static Date localDateToDate(LocalDate ld) {
		return Date.from(ld.atStartOfDay().atZone(systemDefaultZone).toInstant());
	}
	
	/**
	 * 其他时区的UTC时间
	 * @param datetime
	 * @param otherLocale
	 * @return
	 */
	public static ZonedDateTime toZonedDateTime(String pattern, String datetime, Locale otherLocale, ZoneId zoneId) {
		DateTimeFormatter dtf = null;
		if (Objects.isNull(otherLocale)) {
			// 默认英语
			dtf = new DateTimeFormatterBuilder()
				    // case insensitive
				    .parseCaseInsensitive()
				    .appendPattern(pattern)
				    .toFormatter();
		} else {
			// 当地语言
			dtf = new DateTimeFormatterBuilder()
				    // case insensitive
				    .parseCaseInsensitive()
				    .appendPattern(pattern)
				    .toFormatter(otherLocale);
		}
		
		if (Objects.nonNull(zoneId)) {
			dtf = dtf.withZone(zoneId);
		}
		
		ZonedDateTime ldt_other = ZonedDateTime.parse(datetime, dtf);
		return ldt_other;
	}

	/**
	 * 获取指定时间的指定格式
	 * 
	 * @param time
	 * @param pattern
	 * @return
	 */
	public static String formatTime(LocalDateTime time, String pattern) {
		return time.format(DateTimeFormatter.ofPattern(pattern));
	}

	/**
	 * 获取当前时间的指定格式
	 * 
	 * @param pattern
	 * @return
	 */
	public static String formatNow(String pattern) {
		return formatTime(LocalDateTime.now(), pattern);
	}

	/**
	 * 日期加上一个数,根据field不同加不同值,field为ChronoUnit.*
	 * 
	 * @param time
	 * @param number
	 * @param field
	 * @return
	 */
	public static LocalDateTime plus(LocalDateTime time, long number, TemporalUnit field) {
		return time.plus(number, field);
	}

	/**
	 * 日期减去一个数,根据field不同减不同值,field参数为ChronoUnit.*
	 * 
	 * @param time
	 * @param number
	 * @param field
	 * @return
	 */
	public static LocalDateTime minu(LocalDateTime time, long number, TemporalUnit field) {
		return time.minus(number, field);
	}

	/**
	 * 获取两个日期的差 field参数为ChronoUnit.*
	 * 
	 * @param startTime
	 * @param endTime
	 * @param field 单位(年月日时分秒)
	 * @return
	 */
	public static long betweenTwoTime(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit field) {
		Period period = Period.between(LocalDate.from(startTime), LocalDate.from(endTime));
		if (field == ChronoUnit.YEARS)
			return period.getYears();
		if (field == ChronoUnit.MONTHS)
			return period.getYears() * 12 + period.getMonths();
		return field.between(startTime, endTime);
	}

	/**
	 * 获取一天的开始时间，2017,7,22 00:00
	 * 
	 * @param time
	 * @return
	 */
	public static LocalDateTime getDayStart(LocalDateTime time) {
		return time.withHour(0).withMinute(0).withSecond(0).withNano(0);
	}

	/**
	 * 获取一天的结束时间，2017,7,22 23:59:59.999999999
	 * 
	 * @param time
	 * @return
	 */
	public static LocalDateTime getDayEnd(LocalDateTime time) {
		return time.withHour(23).withMinute(59).withSecond(59).withNano(999999999);
	}

	/**
	 * 获取某个日期加了天数之后的日期（去除非工作日）
	 * @param day
	 * @param currentDate
	 * @return
	 */
	public static LocalDate getLatestDispatchDate(int day, LocalDate currentDate) {
		// 一周5个工作日
		int workDay = 5;
		// 计算跨越多少个工作周
		int week = day / workDay;
		LocalDate dispatchDate = currentDate.plusDays(week * 7);
		// 计算跨越工作周后还需要加上的天数
		int remainder = day % workDay;
		while (remainder > 0) {
			dispatchDate = dispatchDate.plusDays(1);
			DayOfWeek dayOfWeek = dispatchDate.getDayOfWeek();
			// 遇到周六日则continue
			if (dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY) {
				continue;
			}
			// 往后推的天数减1
			remainder--;
		}
		return dispatchDate;
	}
	
	/**
	 * 如果当前时间不是零点零分零秒，就获取下一天的零分零点零秒日期。否则，返回当前时间。
	 * @return
	 */
	public static long getNextZeroTime(long time) {
		Calendar calendar1 = Calendar.getInstance();
		calendar1.setTimeInMillis(time);
		calendar1.set(calendar1.get(Calendar.YEAR), calendar1.get(Calendar.MONTH), calendar1.get(Calendar.DAY_OF_MONTH),
				0, 0, 0);
		long zeroTime = calendar1.getTimeInMillis();
		if (zeroTime < time) {
			calendar1.add(Calendar.DATE, 1);
		}
		zeroTime = calendar1.getTimeInMillis();
		return zeroTime;
	}
	
	/**
	 * 转换成指定的时区的时间
	 * @param l
	 * @param timeZone
	 * @param specificTimeZone-为空时,转成系统默认时区的时间
	 * @return
	 */
	public static LocalDateTime toSpecificZoneDateTime(ZonedDateTime zdt, String specificTimeZone) {
    	return toSpecificZoneDateTime(zdt.toLocalDateTime(), zdt.getZone().getId(), specificTimeZone);
    }
	
	/**
	 * 转换成指定的时区的时间
	 * @param l
	 * @param timeZone
	 * @param specificTimeZone-为空时,转成系统默认时区的时间
	 * @return
	 */
	public static LocalDateTime toSpecificZoneDateTime(LocalDateTime l, String timeZone, String specificTimeZone) {
    	ZoneId zone = null;
    	ZoneId specificZone = null;
    	int year = l.getYear();
		int month = l.getMonthValue();
		int date = l.getDayOfMonth();
		int hour = l.getHour();
		int minute = l.getMinute();
		int second = l.getSecond();
		try {
			zone = ZoneId.of(timeZone);
		} catch (Exception e) {
			throw e;
		}
		
		ZonedDateTime zdt = ZonedDateTime.of(year, month, date, hour, minute, second, 0, zone);
		// 获得毫秒数
		Long millis = zdt.toInstant().toEpochMilli();
//		System.out.println(zone.getId() + "时区时间毫秒数" + millis);
//		System.out.println(zone.getId() + "时区时间" + zdt);
		LocalDateTime temp = null;
		// 转成指定时区的时间
		try {
			if (StringUtils.isEmpty(specificTimeZone)) {
				temp = millisToLocalDateTime(millis);
			} else {
				specificZone = ZoneId.of(specificTimeZone);
				temp = millisToLocalDateTime(specificZone, millis);
			}
		} catch (Exception e) {
			throw e;
		}
    	return temp;
    }
	
}
